package com.ccctop.crowd.service.Impl;

import com.ccctop.crowd.api.MySQLRemoteService;
import com.ccctop.crowd.config.Web3jConfig;
import com.ccctop.crowd.contract.CrowdFunding;
import com.ccctop.crowd.entity.po.*;
import com.ccctop.crowd.entity.vo.*;
import com.ccctop.crowd.service.FundService;
import com.ccctop.crowd.util.ResultEntity;
import com.ccctop.crowd.util.Web3jUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.WalletUtils;
import org.web3j.protocol.Web3j;
import org.web3j.tx.RawTransactionManager;
import org.web3j.tx.TransactionManager;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

@Service
public class FundServiceImpl implements FundService {
    @Autowired
    MySQLRemoteService mySQLRemoteService;
    @Autowired
    Web3j web3j;


    @Override
    public ResultEntity<String> createFundRequest(TFundRequestVo fundRequest) throws Exception {
        //1.查找投资该项目的所有投资人
        Integer projectId = fundRequest.getProjectId();
        if (projectId == null) {
            return ResultEntity.failed("项目id不能为空！");
        }
        ResultEntity<List<TInvestor>> investors = mySQLRemoteService.queryInvestors(projectId);
        ArrayList<TFundRequest> requests = null;
        TFundRequestInfo tFundRequestInfo = null;
        if (investors.getResult().equals(ResultEntity.SUCCESS)) {
            //set进行去重，因为可能一个人多次投资
            HashSet<Integer> memberIds = new HashSet<>();
            for (TInvestor investor : investors.getData()) {
                memberIds.add(investor.getMemberId());
            }
            int memberNum = memberIds.size();
            if (memberNum == 0) {
                return ResultEntity.failed("暂无人支持本项目，无法发起提取资金请求！");
            }
            //向智能合约发出请求
            CrowdFunding crowdFunding = getCrowdFunding(fundRequest.getFundApplicantId(), fundRequest.getProjectId(), fundRequest.getPassword());
            //TODO 根据request返回的int值判断结果
            crowdFunding.request(Web3jUtil.unitConversion(fundRequest.getFundNum())).send();

            tFundRequestInfo = new TFundRequestInfo();
            tFundRequestInfo.setTotalMemberNum(memberNum);
            tFundRequestInfo.setCreateDate(new Date());
            tFundRequestInfo.setProjectId(projectId);
            tFundRequestInfo.setStatus(0);
            tFundRequestInfo.setAgreeNum(0);
            tFundRequestInfo.setRefuseNum(0);
            ResultEntity<TFundRequestInfo> result1 = mySQLRemoteService.fundInfoInsert(tFundRequestInfo);
            if (result1.getResult().equals(ResultEntity.FAILED)) {
                throw new Exception(result1.getMessage());
            }
            TFundRequestInfo info = result1.getData();
            requests = new ArrayList<>();
            //构建出资金请求信息
            for (Integer memberId : memberIds) {
                TFundRequest request = new TFundRequest();
                BeanUtils.copyProperties(fundRequest, request);
                request.setReviewerId(memberId);
                request.setInfoId(info.getId());
                requests.add(request);
            }
        } else {
            return ResultEntity.failed(investors.getMessage());
        }
        //2.保存资金请求到数据库
        ResultEntity<String> result = mySQLRemoteService.saveRequests(requests);
        if (result.getResult().equals(ResultEntity.FAILED)) {
            throw new Exception(result.getMessage());
        }
        return result;
    }

    @Override
    public ResultEntity<List<FundRequestVo>> fundInfo(Integer userId) throws Exception {
        //查更本用户有关的需要审核的资金请求
        ResultEntity<List<TFundRequest>> tFundResult = mySQLRemoteService.fundInfo(userId);
        ResultEntity<List<FundRequestVo>> result = null;
        List<FundRequestVo> fundRequestVos = null;
        if (tFundResult.getResult().equals(ResultEntity.SUCCESS)) {
            fundRequestVos = new ArrayList<>();
            for (TFundRequest tFundRequest : tFundResult.getData()) {
                FundRequestVo fundRequestVo = new FundRequestVo();
                BeanUtils.copyProperties(tFundRequest, fundRequestVo);

                //查项目详细信息
                ResultEntity<ProjectPO> project = mySQLRemoteService.getProjectPoByProjectId(tFundRequest.getProjectId());
                //查询该条资金请求详细信息
                ResultEntity<TFundRequestInfo> tFundRequestInfoResultEntity = mySQLRemoteService.selectFundRequestInfoById(tFundRequest.getInfoId());
                if (project.getResult().equals(ResultEntity.SUCCESS) && tFundRequestInfoResultEntity.getResult().equals(ResultEntity.SUCCESS)) {
                    fundRequestVo.setProject(project.getData());
                    TFundRequestInfo requestInfo = tFundRequestInfoResultEntity.getData();
                    BeanUtils.copyProperties(requestInfo, fundRequestVo);
                    fundRequestVo.setCreateDate(new SimpleDateFormat("yyyy-MM-dd").format(requestInfo.getCreateDate()));
                    fundRequestVo.setId(tFundRequest.getId());
                    fundRequestVo.setStatus(tFundRequest.getStatus());
                } else {
                    throw new Exception(project.getMessage() + " " + tFundRequestInfoResultEntity.getMessage());
                }
                //查申请人信息
                ResultEntity<MemberPO> member = mySQLRemoteService.getMemberById(tFundRequest.getFundApplicantId());
                if (member.getResult().equals(ResultEntity.SUCCESS)) {
                    MemberLoginVO memberLoginVO = new MemberLoginVO();
                    BeanUtils.copyProperties(member.getData(), memberLoginVO);
                    fundRequestVo.setMember(memberLoginVO);
                } else {
                    throw new Exception(member.getMessage());
                }
                fundRequestVos.add(fundRequestVo);
            }
            result = ResultEntity.successWithData(fundRequestVos);
        } else {
            throw new Exception(tFundResult.getMessage());
        }
        return result;
    }

    @Override
    public ResultEntity<String> fundAgree(FundVoteVo fundVoteVo) throws Exception {
        Integer itemId = fundVoteVo.getItemId();
        //检查是否已经处理过本请求
        if (checkForFundRequest(itemId)) {
            //智能合约进行投票更改
            CrowdFunding crowdFunding = getCrowdFunding(fundVoteVo.getUserId(), fundVoteVo.getProjectId(), fundVoteVo.getPassword());
            crowdFunding.verify(true).send();
            ResultEntity<String> result = mySQLRemoteService.fundAgree(itemId);
            if (result.getResult().equals(ResultEntity.FAILED)){
                throw new Exception(result.getMessage());
            }
            mySQLRemoteService.agreeIncrease(itemId);
            return result;
        } else {
            throw new Exception("已经处理过本请求！");
        }
    }

    @Override
    public ResultEntity<String> fundRefuse(FundVoteVo fundVoteVo) throws Exception {
        Integer itemId = fundVoteVo.getItemId();
        //检查是否已经处理过本请求
        if (checkForFundRequest(itemId)) {
            //智能合约进行投票更改
            CrowdFunding crowdFunding = getCrowdFunding(fundVoteVo.getUserId(), fundVoteVo.getProjectId(), fundVoteVo.getPassword());
            crowdFunding.verify(false).send();
            ResultEntity<String> result = mySQLRemoteService.fundRefuse(itemId);
            if (result.getResult().equals(ResultEntity.FAILED)){
                throw new Exception(result.getMessage());
            }
            mySQLRemoteService.refuseIncrease(itemId);
            return result;
        } else {
            throw new Exception("已经处理过本请求！");
        }
    }

    @Override
    public void supportProject(InvestorVo investor) throws Exception {
        //对智能合约操作
        CrowdFunding crowdFunding = getCrowdFunding(investor.getMemberId(), investor.getProjectId(), investor.getPassword());
        //投资(同步等待)
        crowdFunding.contribute(Web3jUtil.unitConversion(investor.getMoneyNum())).send();
        //存入数据库
        TInvestor tInvestor = new TInvestor();
        BeanUtils.copyProperties(investor, tInvestor);
        ResultEntity<String> result = mySQLRemoteService.supportProject(tInvestor);
        if (result.getResult().equals(ResultEntity.FAILED)) {
            throw new Exception(result.getMessage());
        }
        //更新对于项目所筹资金数
        ProjectPO projectPO = new ProjectPO();
        projectPO.setId(investor.getProjectId());
        projectPO.setSupportmoney(investor.getMoneyNum().longValue());
        ResultEntity<String> result1 = mySQLRemoteService.updateProjectSupportMoneyById(projectPO);
        if (result1.getResult().equals(ResultEntity.FAILED)) {
            throw new Exception(result1.getMessage());
        }
    }

    @Override
    public void tryWithdraw(WithdrawVo withdrawVo) throws Exception {
        CrowdFunding crowdFunding = getCrowdFunding(withdrawVo.getUserId(), withdrawVo.getProjectId(), withdrawVo.getPassword());
        //TODO 根据返回值进行判断是否成功
        crowdFunding.withdraw().send();
    }

    private boolean checkForFundRequest(Integer itemId) {
        ResultEntity<TFundRequest> result = mySQLRemoteService.fundQuery(itemId);
        if (result.getResult().equals(ResultEntity.SUCCESS)) {
            TFundRequest data = result.getData();
            if (data != null) {
                //没处理过
                return data.getStatus() == 0;
            }
        }
        return true;
    }

    //获取智能合约
    private CrowdFunding getCrowdFunding(Integer userId, Integer projectId, String password) throws Exception {
        //加载凭证
        ResultEntity<TWallet> wallet = mySQLRemoteService.selectWalletByUserId(userId);
        Credentials credentials = null;
        if (wallet.getResult().equals(ResultEntity.SUCCESS)) {
            TWallet walletData = wallet.getData();
            String walletName = walletData.getWallet();
            File file = new File(Web3jConfig.WALLET_PATH_PREFIX + walletName);
            credentials = WalletUtils.loadCredentials(password,file);
        } else {
            throw new Exception(wallet.getMessage());
        }
        //查询合约地址
        String address = null;
        ResultEntity<TContractAddress> addressResultEntity = mySQLRemoteService.selectContractAddressByUserId(projectId);
        if (addressResultEntity.getResult().equals(ResultEntity.SUCCESS)) {
            TContractAddress contractAddress = addressResultEntity.getData();
            address = contractAddress.getContractAddress();
        } else {
            throw new Exception(addressResultEntity.getMessage());
        }
        //加载合约
        TransactionManager transactionManager = new RawTransactionManager(
                web3j,
                credentials
        );
        CrowdFunding crowdFunding = Web3jUtil.loadContract(address, web3j, transactionManager);
        return crowdFunding;
    }

}
